<?php
/* ----- 非法请求 ----- */
defined('IN_PMF') || die('403 Forbidden !!!');

/**
 * Fsock模拟Get/Post
 * 注意:此类仍在测试中
 */
class Fsock {
    public $blnDownload = false;
    public $strMethod = 'GET';
    public $strHost = '';
    public $strUri = '';
    public $intPort = 80;
    public $floTimeout = 60; // 秒
    public $arrGet = array();
    public $arrPost = array();
    public $arrCookie = array();
    public $arrHeader = array();
    private $strErrMsg = '';
    private $strRequest = '';
    private $objFP = null;
    
    /**
     * 构造函数
     */
    public function __construct($strMethod = 'get', $strUri = '', $blnDownload = false) {
        $this->strMethod = $strMethod;
        $this->strUri = $strUri;
        $this->blnDownload = $blnDownload;
    }
    
    /**
     * 处理请求的数组
     */
    private function getStrFromArr($strType = 'get') {
        $strRe = '';
        $strConnect = '&';
        $arr = array();
        switch ($strType) {
            case 'get':
                $arr = $this->arrGet;
                count($arr) > 0 && $strRe .= '?';
                break;
            case 'cookie':
                $arr = $this->arrCookie;
                $strConnect = '; ';
                break;
            case 'post':
                $arr = $this->arrPost;
                break;
        }
        $blnFirst = true;
        foreach ($arr as $key => $val) {
            $blnFirst ? $blnFirst = false : $strRe .= $strConnect;
            $strRe .= urlencode($key) . '=' . urlencode($val);
        }
        return $strRe;
    }
    
    /**
     * 验证参数
     */
    private function checkParameters() {
        $blnTemp = true;
        $this->strMethod = strtoupper($this->strMethod);
        if (!in_array($this->strMethod, array('GET', 'POST'), true)) {
            $blnTemp = false;
            $this->strErrMsg .= 'WRONG_METHOD;';
        }
        if ($blnTemp && (!is_string($this->strUri) || empty($this->strUri))) {
            $blnTemp = false;
            $this->strErrMsg .= 'WRONG_URI';
        } elseif (!$this->strHost) {
            $arrTemp = parse_url($this->strUri);
            isset($arrTemp['host']) && $this->strHost = $arrTemp['host'];
        }
        if ($blnTemp && (!is_string($this->strHost) || empty($this->strHost))) {
            $blnTemp = false;
            $this->strErrMsg .= 'WRONG_HOST;';
        }
        if ($blnTemp && !is_array($this->arrCookie)) {
            $blnTemp = false;
            $this->strErrMsg = 'WRONG_COOKIE;';
        }
        if ($blnTemp && !is_array($this->arrGet)) {
            $blnTemp = false;
            $this->strErrMsg = 'WRONG_GET;';
        }
        if ($blnTemp && !is_array($this->arrPost)) {
            $blnTemp = false;
            $this->strErrMsg = 'WRONG_POST;';
        }
        if ($blnTemp && !is_array($this->arrHeader)) {
            $blnTemp = false;
            $this->strErrMsg = 'WRONG_HEADER;';
        }
        // More ...
        return $blnTemp;
    }
    
    /**
     * 取上一次的请求信息
     */
    public function getLastRequest() {
        return $this->strRequest;
    }
    
    /**
     * 取错误信息
     */
    public function getErrMsg() {
        return $this->strErrMsg;
    }
    
    /**
     * 发送请求
     */
    public function makeRequest() {
        if ($this->checkParameters()) {
            $strRN = "\r\n";
            $strRequest = $this->strMethod . ' ' . $this->strUri . $this->getStrFromArr('get') . ' HTTP/1.1' . $strRN;
            $strRequest .= 'Host: '. $this->strHost . $strRN;
            $strRequest .= 'User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.117 Safari/537.36' . $strRN;
            $strRequest .= 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' . $strRN;
            foreach ($this->arrHeader as $key => $val) {
                $strRequest .= $key . ': ' . $val . $strRN;
            }
            if (is_array($this->arrCookie) && count($this->arrCookie) > 0) {
                $strRequest .= 'Cookie: ' . $this->getStrFromArr('cookie') . $strRN;
            }
            if ('POST' == $this->strMethod && count($this->arrPost) > 0) {
                $strTemp = $this->getStrFromArr('post');
                $strRequest .= 'Content-Type: application/x-www-form-urlencoded' . $strRN;
                $strRequest .= 'Content-Length: ' . strlen($strTemp) . $strRN . $strRN;
                $strRequest .= $strTemp;
            } else {
                $strRequest .= $strRN;
            }
            $this->strRequest = $strRequest;
            $errno = $errstr = $fp = false;
            if (($fp = fsockopen($this->strHost, $this->intPort, $errno, $errstr)) == false) {
                $this->strErrMsg .= 'FSOCKOPEN_ERROR: ' . $errstr . '(' . $errno . ');';
                return false;
            }
            if (fwrite($fp, $strRequest) === false) {
                $this->strErrMsg .= 'REQUEST_ERROR: FWRITE;'; 
                return false;
            } else {
                stream_set_blocking($fp, !$this->blnDownload);
                stream_set_timeout($fp, 0, ($this->floTimeout * 1000));
                $this->objFP = $fp;
                return $fp;
            }
        }
        return false;
    }
    
    /**
     * 下载文件
     */
    public function saveTo($strPath) {
        $blnRe = false;
        $objFP = $this->objFP;
        if ($objFP && is_string($strPath) && !empty($strPath)) {
            File::makeDir(dirname($strPath));
            $fh = fopen($strPath, 'wb');
            $arrInfo = stream_get_meta_data($objFP);
            $blnRemovedHeader = false;
            while ((!feof($objFP)) && (!isset($arrInfo['timed_out']) || !$arrInfo['timed_out'])) {
                $strTemp = fgets($objFP, 4096);
                if (!$blnRemovedHeader) {
                    $blnRemovedHeader = ("\r\n" == $strTemp);
                } else {
                    fwrite($fh, $strTemp);
                }
                $arrInfo = stream_get_meta_data($objFP);
            }
            fclose($fh);
            fclose($objFP);
            $blnRe = true;
        }
        return $blnRe;
    }
    
    /**
     * 取结果
     */
    public function getResult() {
        $strRe = '';
        $objFP = $this->objFP;
        if ($objFP) {
            $arrInfo = stream_get_meta_data($objFP);
            $blnRemovedHeader = false;
            while ((!feof($objFP)) && (!isset($arrInfo['timed_out']) || !$arrInfo['timed_out'])) {
                $strTemp = fgets($objFP, 4096);
                if (!$blnRemovedHeader) {
                    $blnRemovedHeader = ("\r\n" == $strTemp);
                } else {
                    $strRe .= $strTemp;
                }
                $arrInfo = stream_get_meta_data($objFP);
            }
            fclose($objFP);
        }
        return $strRe;
    }
    
}